package com.smart.common.utils;

import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.smart.common.constant.Constants;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ConnectException;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.net.URLConnection;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Map;

/**
 * Http请求工具
 *
 * @author wf
 * @version 1.0.0
 * @since 2023/4/19
 */
@Slf4j
public class HttpUtil {

    /**
     * Post请求
     *
     * @param url     请求地址
     * @param body    请求参数
     * @param headers 请求头
     * @return String
     */
    public static String postJson(String url, String body, Map<String, String> headers) {
        return post(url, body, headers, "application/json");
    }

    /**
     * Post请求
     *
     * @param url  请求地址
     * @param body 请求参数
     * @return String
     */
    public static String postJson(String url, String body) {
        return post(url, body, null, "application/json");
    }

    /**
     * Post请求
     *
     * @param url         请求地址
     * @param body        请求参数
     * @param headers     请求头
     * @param contentType contentType
     * @return String
     */
    public static String post(String url, String body, Map<String, String> headers, String contentType) {
        if (StringUtil.isBlank(url)) {
            throw new RuntimeException("请求地址不能为空！");
        }
        LocalDateTime now = LocalDateTime.now();
        String time = now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss:SSS"));
        log.error("============================ 发送请求 {} ============================", time);
        log.info("URL - {}", url);
        HttpRequest request = HttpRequest.post(url);
        // 追加contentType
        if (StringUtil.isNotBlank(contentType)) {
            request = request.contentType(contentType);
            log.info("content-type - {}", contentType);
        }
        // 追加请求头
        if (headers != null) {
            for (String key : headers.keySet()) {
                String value = headers.get(key);
                request = request.header(key, value);
                log.info("header - {}:{}", key, value);
            }
        }
        if (StringUtil.isNotBlank(body)) {
            request = request.body(body);
            log.info("参数 - {}", body);
        }
        // 追加请求体
        HttpResponse response = request.execute();
        if (!response.isOk()) {
            log.error("发送请求失败 - {}", response.body());
            throw new RuntimeException("发送请求失败！");
        }
        log.info("发送请求成功 - {}", response.body());
        return response.body();
    }

    /**
     * Get请求
     *
     * @param url 请求地址
     * @return String
     */
    public static String get(String url) {
        return get(url, null);
    }

    /**
     * Get请求
     *
     * @param url  请求地址
     * @param body 参数
     * @return String
     */
    public static String get(String url, String body) {
        return get(url, body, null);
    }

    /**
     * Get请求
     *
     * @param url     请求地址
     * @param body    参数
     * @param headers 请求头
     * @return String
     */
    public static String get(String url, String body, Map<String, String> headers) {
        return get(url, body, headers, null);
    }

    /**
     * Get请求
     *
     * @param url         请求地址
     * @param body        参数
     * @param headers     请求头
     * @param contentType contentType
     * @return String
     */
    public static String get(String url, String body, Map<String, String> headers, String contentType) {
        if (StringUtil.isBlank(url)) {
            throw new RuntimeException("请求地址不能为空！");
        }
        LocalDateTime now = LocalDateTime.now();
        String time = now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss:SSS"));
        log.error("============================ 发送请求 {} ============================", time);
        if (StringUtil.isNotBlank(body)) {
            log.info("参数 - {}", body);
            StringBuilder sb = new StringBuilder();
            JSONObject params = JSON.parseObject(body);
            params.keySet().forEach(x -> {
                sb.append(x).append("=").append(params.get(x)).append("&");
            });
            if (sb.length() > 0) {
                url = url + "?" + sb.substring(0, sb.length() - 1);
            }
        }
        log.info("URL - {}", url);
        HttpRequest request = HttpRequest.get(url);
        // 追加contentType
        if (StringUtil.isNotBlank(contentType)) {
            request = request.contentType(contentType);
            log.info("content-type - {}", contentType);
        }
        // 追加请求头
        if (headers != null) {
            for (String key : headers.keySet()) {
                String value = headers.get(key);
                request = request.header(key, value);
                log.info("header - {}:{}", key, value);
            }
        }
        // 追加请求体
        HttpResponse response = request.execute();
        if (!response.isOk()) {
            log.error("发送请求失败 - {}", response.body());
            throw new RuntimeException("发送请求失败！");
        }
        log.info("发送请求成功 - {}", response.body());
        return response.body();
    }

    /**
     * 向指定 URL 发送GET方法的请求
     *
     * @param url 发送请求的 URL
     * @return 所代表远程资源的响应结果
     */
    public static String sendGet(String url) {
        return sendGet(url, StringUtil.EMPTY);
    }

    /**
     * 向指定 URL 发送GET方法的请求
     *
     * @param url   发送请求的 URL
     * @param param 请求参数，请求参数应该是 name1=value1&name2=value2 的形式。
     * @return 所代表远程资源的响应结果
     */
    public static String sendGet(String url, String param) {
        return sendGet(url, param, Constants.UTF8);
    }

    /**
     * 向指定 URL 发送GET方法的请求
     *
     * @param url         发送请求的 URL
     * @param param       请求参数，请求参数应该是 name1=value1&name2=value2 的形式。
     * @param contentType 编码类型
     * @return 所代表远程资源的响应结果
     */
    public static String sendGet(String url, String param, String contentType) {
        StringBuilder result = new StringBuilder();
        BufferedReader in = null;
        try {
            String urlNameString = StringUtil.isNotBlank(param) ? url + "?" + param : url;
            log.info("sendGet - {}", urlNameString);
            URL realUrl = new URL(urlNameString);
            URLConnection connection = realUrl.openConnection();
            connection.setRequestProperty("accept", "*/*");
            connection.setRequestProperty("connection", "Keep-Alive");
            connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            connection.connect();
            in = new BufferedReader(new InputStreamReader(connection.getInputStream(), contentType));
            String line;
            while ((line = in.readLine()) != null) {
                result.append(line);
            }
            log.info("recv - {}", result);
        } catch (ConnectException e) {
            log.error("调用HttpUtils.sendGet ConnectException, url=" + url + ",param=" + param, e);
        } catch (SocketTimeoutException e) {
            log.error("调用HttpUtils.sendGet SocketTimeoutException, url=" + url + ",param=" + param, e);
        } catch (IOException e) {
            log.error("调用HttpUtils.sendGet IOException, url=" + url + ",param=" + param, e);
        } catch (Exception e) {
            log.error("调用HttpsUtil.sendGet Exception, url=" + url + ",param=" + param, e);
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (Exception ex) {
                log.error("调用in.close Exception, url=" + url + ",param=" + param, ex);
            }
        }
        return result.toString();
    }

    /**
     * 向指定 URL 发送POST方法的请求
     *
     * @param url   发送请求的 URL
     * @param param 请求参数，请求参数应该是 name1=value1&name2=value2 的形式。
     * @return 所代表远程资源的响应结果
     */
    public static String sendPost(String url, String param) {
        PrintWriter out = null;
        BufferedReader in = null;
        StringBuilder result = new StringBuilder();
        try {
            String urlNameString = url;
            log.info("sendPost - {}", urlNameString);
            URL realUrl = new URL(urlNameString);
            URLConnection conn = realUrl.openConnection();
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            conn.setRequestProperty("Accept-Charset", "utf-8");
            conn.setRequestProperty("contentType", "utf-8");
            conn.setDoOutput(true);
            conn.setDoInput(true);
            out = new PrintWriter(conn.getOutputStream());
            out.print(param);
            out.flush();
            in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
            String line;
            while ((line = in.readLine()) != null) {
                result.append(line);
            }
            log.info("recv - {}", result);
        } catch (ConnectException e) {
            log.error("调用HttpUtils.sendPost ConnectException, url=" + url + ",param=" + param, e);
        } catch (SocketTimeoutException e) {
            log.error("调用HttpUtils.sendPost SocketTimeoutException, url=" + url + ",param=" + param, e);
        } catch (IOException e) {
            log.error("调用HttpUtils.sendPost IOException, url=" + url + ",param=" + param, e);
        } catch (Exception e) {
            log.error("调用HttpsUtil.sendPost Exception, url=" + url + ",param=" + param, e);
        } finally {
            try {
                if (out != null) {
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (IOException ex) {
                log.error("调用in.close Exception, url=" + url + ",param=" + param, ex);
            }
        }
        return result.toString();
    }

    public static String doPostXml(String url, String xml) {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse response = null;
        String resultString = "";
        try {
            HttpPost httpPost = new HttpPost(url);
            httpPost.addHeader("Content-Type","text/xml;charset=UTF-8");
//            httpPost.setHeader(key,value);                            //设置post请求的请求头
            StringEntity entity = new StringEntity(xml, "UTF-8");
            httpPost.setEntity(entity);
            response = httpClient.execute(httpPost);
            if (response.getStatusLine().getStatusCode() == 200) {
                resultString = EntityUtils.toString(response.getEntity(), "utf-8");
                //System.out.println("返回结果："+resultString);
            }else{
                resultString = EntityUtils.toString(response.getEntity(), "utf-8");
                //System.out.println("返回结果："+resultString);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
                httpClient.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return resultString;
    }
}
